import ilog.concert.IloColumn;
import ilog.concert.IloConversion;
import ilog.concert.IloException;
import ilog.concert.IloLPMatrix;
import ilog.concert.IloLinearNumExpr;
import ilog.concert.IloNumVar;
import ilog.concert.IloNumVarType;
import ilog.concert.IloObjective;
import ilog.concert.IloRange;
import ilog.cplex.IloCplex;
import java.util.List;
import java.util.ArrayList;

public class masterproblem extends IloCplex {

	
	int w;	// Number of weeks W
	int s;	// Number of tours S
	int t;	// Time periods
	
	
	double[][] S;		//coverage of the demand of tour s in time period t
	double[] S_we;		// set of all tour which include a weekend
	int[] D;			// Demand in period t

	
	
	IloCplex cplex;
	IloNumVar[][] x;
	IloNumVar[] u;
	
	
	
	
	public masterproblem ( int w, int s, int t, double[][] S, double[] S_we, int[] D) throws IloException{
		this.w = w;
		this.s = s;
		this.t = t;
		this.S = S;
		this.S_we = S_we;
		this.D = D;
		
		
	}
	
	public int solvemaster() throws IloException{
		this.cplex = new IloCplex();
		cplex.setParam(IloCplex.BooleanParam.NumericalEmphasis, true);
		this.x = new IloNumVar[s][w];
		this.u = new IloNumVar[t];
		
		for (int a = 0; a < s; a++ ){
			for (int b = 0; b < w; b++){
				x[a][b] = cplex.numVar(0,1, IloNumVarType.Bool);
			}
		}
			
		for (int c = 0; c < t; c++ ){
			u[c] = cplex.numVar(0, 2, IloNumVarType.Int);
		}	
		
	
	
		
		
		
	//----------------OBF----------------
	IloLinearNumExpr objfunc = cplex.linearNumExpr();
		
	for (int c = 0; c < t; c++ ){
		objfunc.addTerm(1.0, u[c]);
	}
	cplex.addMinimize(objfunc);
	
	
	IloLinearNumExpr st = cplex.linearNumExpr();
	
	
	
	
	List<IloRange> constraints = new ArrayList<IloRange>();
	
	
	//----------------CS2----------------
	// Demand Constraint 
	for(int c = 0; c < t; c++){
		st.clear();
		for (int a = 0; a < s; a++ ){
			for (int b = 0; b < w; b++ ){
				st.addTerm(S[a][c], x[a][b]);
			}
		}
		st.addTerm(1.0, u[c]);
		constraints.add(cplex.addGe(st, D[c]));
	}
	
	
	
	//----------------CS3----------------
    //Only one tour per week 
	for (int b = 0; b < w; b++){
		st.clear();
		for (int a = 0; a < s; a++ ){
			st.addTerm(1.0, x[a][b]);		
		}
		constraints.add(cplex.addEq(st, 1));	
	}

	
	//----------------CS4----------------
	//only permitted tours follow after each other Su late -> Mo early and day weeks 1-9
	for(int c = 0; c <2; c++){
		for (int b = 0; b < (w-1); b++){
			st.clear();
			for (int a = 0; a < s; a++ ){
				st.addTerm(S[a][c],x[a][b]);
				st.addTerm(S[a][t-1],x[a][b+1]);
			}		
			constraints.add(cplex.addLe(st, 1));
			
		}
	}
	
	
	//----------------CS5----------------
	//only permitted tours follow after each other	 weeks 10
	for (int b = 0; b < (w-1); b++){
		st.clear();
		for (int a = 0; a < s; a++ ){
			st.addTerm(S[a][1],x[a][b]);
			st.addTerm(S[a][t-2],x[a][b+1]);
		}		
		constraints.add(cplex.addLe(st, 1));
		
	}
	
	//----------------CS6----------------
		//only permitted tours follow after each other Su late -> Mo early and day weeks 10to1 transition
		for(int c = 0; c <2; c++){
			st.clear();
			for (int a = 0; a < s; a++ ){
				st.addTerm(S[a][c],x[a][9]);
				st.addTerm(S[a][t-1],x[a][0]);
			}		
			constraints.add(cplex.addLe(st, 1));
			
		}
		
	
		//----------------CS7----------------
		//only permitted tours follow after each other	 weeks 10
		st.clear();
		for (int a = 0; a < s; a++ ){
			st.addTerm(S[a][0],x[a][9]);
			st.addTerm(S[a][t-2],x[a][0]);
		}		
		constraints.add(cplex.addLe(st, 1));
			
			
	
//	
//	//----------------CS7----------------
//    //only work on two consecutive weekends
//	for (int b = 0; b < w-1; b++){
//		int[] we = we();
//		st.clear();
//		for (int a = 0; a < we.length; a++ ){
//			st.addTerm(1.0, x[we[a]][b]);				//!!!!!!!!!!!!! not sure yet -> refine
//			st.addTerm(1.0, x[we[a]][b+1]);				//!!!!!!!!!!!!! not sure yet -> refine
//		}
//		constraints.add(cplex.addLe(st, 1));
//	}
//	
//	
//
//	//----------------CS8----------------
//    //only work on two consecutive weekends^
//	int[] we = we();
//	st.clear();
//	for (int a = 0; a < we.length; a++ ){
//		st.addTerm(1.0, x[we[a]][9]);
//		st.addTerm(1.0, x[we[a]][0]);
//	}
//	constraints.add(cplex.addLe(st, 1));
//	
//	
	
	cplex.solve();
	cplex.solveFixed();
		
	for (int a = 0; a < s; a++ ){
		for (int b = 0; b < w; b++){
			System.out.print(cplex.getValue(x[a][b]) + " , ");
		}
		System.out.println();
	}
	for (int i=0;i<constraints.size();i++) {
		System.out.println("dual constraint "+(i+1)+"  = "+cplex.getDual(constraints.get(i)));
//		System.out.println("slack constraint "+(i+1)+" = "+cplex.getSlack(constraints.get(i)));
	}
		
	
		
		
		
	for (int c = 0; c < t; c++ ){
		System.out.print(cplex.getValue(u[c]) + " | ");
	}
	System.out.println();
	return (int) cplex.getObjValue();
		
	
	}
	
	
	
	
	
	
	
	public static void main(String[] args) throws IloException {
		int w = 			10;
		int s = 			3;
		int t = 			21;
		double[][] S = 		{{1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0},{1,0,0,1,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0},{1,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0}};
		double[] S_we = 	new double[1];
		int[] D =			new int[t];
		
		for(int k=0; k < D.length; k++){
			D[k]= 8;
		}
		
		
		int solution =0;
		masterproblem m= new masterproblem(w, s, t, S, S_we, D);
		try{
			solution = m.solvemaster();
		} catch (IloException e){
			e.printStackTrace();
            System.err.println("Concert exception caught: " + e);
		}
				
	}
	

	
	
	
	public int[] inf(int s){
		int[] q = null;
//		if(s < 7 || s==9 || s==12 || s==15 || s==18 ){
			int[] w ={0};
			return w;
//		}
//		if(s == 7 || s == 10 || s == 13 || s == 16 || s == 19){
//			int[] w ={0, 9, 12, 15, 18};
//			return w;
//		}
//		if(s == 8 || s == 11 || s == 14 || s == 17 || s == 20 ){
//			int[] w ={0, 1, 9, 10, 12, 13, 15, 16, 18, 19};
//			return w;
//		}
//		return q;
	}	


	public static int[] we (){
		int[] we = new int[18];
		for(int a = 0; a < we.length; a++){
			we[a]= a+3;
						}
		return  we;
	}
	
	
}
